# coding:utf-8
__author__ = 'admin zhoushuang'
__date__ = '2016/10/8'

from socket import socket, AF_INET, SOCK_STREAM
import gvars
import StringIO
import getopt
import sys
import os.path
import base64


def extract_param(reqdict, param_des):
    """Extract parameters from request dict

    :param reqdict:  raw request k-v dict
    :param param_des: params discription tuple, as (('param1_name', 1), ('param2_name', 0), )
    :return params_dict: validated params dict
    :raise ValueError: some parameter is not setted in reqdict
    """
    rtn_dict = {}
    for name, nf in param_des:
        value = reqdict.get(name)
        if not value and nf == 1:
            raise ValueError('parameter %s is not setted.' % name)
        elif not value and nf == 0:
            pass
        else:
            rtn_dict[name] = value
    return rtn_dict


def sendrequest(address, request_dict):
    """Send Request to remote host

    :param address:  tuple(ip_str, port_int)   remote host address
    :param request_dict:    request parameter's dict
    :return:  the module handler' output content (self.echo.write())
    """
    s = socket(AF_INET, SOCK_STREAM)
    s.connect(address)

    socket_in = s.makefile('rt')
    socket_out = s.makefile('wt')

    content = 'module=' + request_dict['module'] + '\n'
    for key, val in request_dict.items():
        content += key + '=' + val + '\n'
    content += '\n' + gvars.EOFSTR + '\n'
    socket_out.write(content)
    socket_out.flush()
    rstr = ''
    while True:
        line = socket_in.readline()
        rstr += line
        if line.startswith(gvars.EOFSTR):
            break

    socket_out.close()
    socket_in.close()
    s.close()
    return rstr


def check_response_string(response_str):
    """检查远端返回的字符串是否包含ERROR， FAILED 字符， 如果有，则返回False , 没有，就返回True

    :param response_str:  agent 端返回的字符串
    :return:    True 成功，无报错。  False 失败，出有错误
    """
    f = StringIO.StringIO(response_str)
    for line in f.readlines():
        for tag in gvars.FAILED_TAGS:
            r = False if line.upper().find(tag) > 0 else True
            if not r:
                f.close()
                raise ValueError("Response has ERROR or FAILED string, remote execution failed")
    f.close()


def parse_cmdline(sys_argvs):
    """解析命令行参数 .
    :param sys_argvs:  命令行字符串, 必须满足格式 oph [-h host1,host2,...] [-g hostgroup,hg2,..] [module_command] [param=value]
    :return:  (rtn_dict, hlist, glist) : rtn_dict 请求参数， hlist: -h 指定的主机列表， glist: -g 指定的组列表
    """
    hlist, glist, rtn_dict = None, None, None
    if len(sys_argvs) <= 3:
        raise ValueError('the cmdline sys_argvs less than 3. '
                         'It must match : oph [-h host] [-g hostgroup] [module_command] [param=value].... ')

    opts, argvs = getopt.getopt(sys_argvs[1:], 'h:g:')

    if len(argvs) < 1:
        raise ValueError('need module parameters. '
                         'It must match : oph [-h host] [-g hostgroup] [module_command] [param=value].... ')

    for name, value in opts:
        if name == '-h':
            hlist = value.split(',')
        if name == '-g':
            glist = value.split(',')

    rtn_dict = {'module': 'mod_'+argvs[0]}
    param_dict = parse_argv(argvs[1:])
    rtn_dict.update(param_dict)
    return rtn_dict, hlist, glist


def parse_argv(argvs):
    """parse_argv( argvs:list ) -> dict  convert  key1=value  key2=value ... parameter in sys.argvs to dict

    :param argvs:   [key = values] parts in sys.argvs
    :return:  dict
    """
    rtn_dict = {}
    while argvs:
        item = argvs[0]
        try:
            i = item.index('=')
        except ValueError:
            print "#Error, {} is not formated as key=value".format(item)
            raise ValueError('%s is not formated as key=value' % item)
        else:
            opt, optarg = item[:i], item[i + 1:]

        if not optarg.startswith('"') and not optarg.startswith("'"):
            rtn_dict[opt] = optarg
            argvs = argvs[1:]
            continue

        elif optarg.startswith('"') or optarg.startswith("'"):
            m = optarg[0]
            if optarg.endswith(m):
                rtn_dict[opt] = optarg[1:-1]
                argvs = argvs[1:]
                continue
            else:
                flag = False
                argvs = argvs[1:]
                while argvs:
                    if argvs[0].endswith(m):
                        optarg += ' ' + argvs[0]
                        argvs = argvs[1:]
                        flag = True
                        break
                    else:
                        optarg += ' ' + argvs[0]
                        argvs = argvs[1:]
                if flag:
                    rtn_dict[opt] = optarg[1:-1]
                else:
                    print '#Error {} has " ,but not completed'.format(opt)
                    raise ValueError('%s has ", but don\'t has end "' % opt)
    return rtn_dict


def call_module_request_side(reqdict, address_tuple):
    """ 调用handler模块的请求端方法 handle_request_side
    :param req_dict:  请求参数，
    :param address_tuple:  远端agent的地址 (ip， port)
    :return:
    """
    req_dict = reqdict.copy()
    modulename = req_dict['module']
    module = sys.modules.get(modulename, None)
    # print sys.modules
    # print globals()
    if module is None:
        raise NameError('There is no module named %s' % modulename)
    handler = getattr(module, 'gethandler', None)()
    print 'CALLING @@@ %s %s' % address_tuple
    handler.handle_request_side(req_dict, address_tuple)


def file2base64(filepath):
    size = os.path.getsize(filepath)
    if size > gvars.FILESIZE:
        raise ValueError("%s size is bigger than %d " % (filepath, gvars.FILESIZE))
    with open(filepath, 'r') as f:
        byts = f.read()
        b64 = base64.b64encode(byts)
    return b64


def file2bas64_yield(filepath):
    with open(filepath, 'r') as fin:
        while True:
            bs = fin.read(gvars.FILESIZE)
            if not bs:
                return
            yield base64.b64encode(bs)








